package com.cryptoneedle.garden.service.garden.source.constraint;


import com.bubbles.engine.data.core.repository.BaseRepository;
import com.bubbles.engine.data.core.service.BaseService;
import com.cryptoneedle.garden.entity.source.constraint.SourceConstraintPrimary;
import com.cryptoneedle.garden.entity.source.metadata.SourceCatalog;
import com.cryptoneedle.garden.entity.source.metadata.SourceDatabase;
import com.cryptoneedle.garden.key.source.constraint.ConstraintColumnKey;
import com.cryptoneedle.garden.repository.source.constraint.SourceConstraintPrimaryRepository;
import com.cryptoneedle.garden.service.crud.garden.source.*;
import com.cryptoneedle.garden.service.util.JdbcUtil;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>description: 源数据源-主键约束 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-20
 */
@Slf4j
@Service
public class ConstraintPrimaryService extends BaseService<SourceConstraintPrimary, ConstraintColumnKey> {

    @Resource
    private ConstraintPrimaryService constraintPrimaryService;
    @Resource
    private SourceConstraintPrimaryRepository sourceConstraintPrimaryRepository;

    @Override
    public BaseRepository<SourceConstraintPrimary, ConstraintColumnKey> getRepository() {
        return this.sourceConstraintPrimaryRepository;
    }

    @Autowired
    private FoundSourceService select;
    @Autowired
    private AddSourceService add;
    @Autowired
    private PatchSourceService patch;
    @Autowired
    private SaveSourceService save;
    @Autowired
    private DeleteSourceService delete;

    @Transactional
    public void syncDatabase(SourceCatalog catalog, SourceDatabase database) {
        JdbcTemplate jdbcTemplate = JdbcUtil.getJdbcTemplate(catalog);
        List<SourceConstraintPrimary> constraintPrimaries = jdbcTemplate.query(
                catalog.getDatabaseType().getDatabase().getConstraintPrimarySql(database.getDatabaseName()),
                (resultSet, rowNum) -> {
                    SourceConstraintPrimary constraintPrimary = new SourceConstraintPrimary()
                            .setCatalogName(database.getCatalogName())
                            .setDatabaseName(database.getDatabaseName())
                            .setTableName(resultSet.getString("tableName"))
                            .setConstraintName(resultSet.getString("constraintName"))
                            .setColumnName(resultSet.getString("columnName"))
                            .setPosition(resultSet.getInt("position"));
                    return constraintPrimary;
                });

        constraintPrimaryService.compareData(database, constraintPrimaries);
    }

    @Transactional
    public void compareData(SourceDatabase database, List<SourceConstraintPrimary> dealList) {
        List<SourceConstraintPrimary> originList = select.constraintPrimaries(database);
        // 已存在
        Map<String, SourceConstraintPrimary> originMap = Maps.uniqueIndex(originList, origin -> origin.constraintPrimaryKey().toString());
        // 待处理
        Map<String, SourceConstraintPrimary> dealMap = Maps.uniqueIndex(dealList, deal -> deal.constraintPrimaryKey().toString());

        // 新增
        List<SourceConstraintPrimary> extraList = dealList.stream()
                .filter(deal -> !originMap.containsKey(deal.constraintPrimaryKey().toString())).toList();

        // 保存
        List<SourceConstraintPrimary> existsList = originList.stream()
                .filter(origin -> dealMap.containsKey(origin.constraintPrimaryKey().toString()))
                .peek(origin -> {
                    SourceConstraintPrimary deal = dealMap.get(origin.constraintPrimaryKey().toString());
                    origin.setPosition(deal.getPosition());
                }).toList();

        // 移除
        List<SourceConstraintPrimary> missList = originList.stream().filter(item -> !dealMap.containsKey(item.constraintPrimaryKey().toString())).toList();

        add.constraintPrimarys(extraList);
        save.constraintPrimarys(existsList);
        delete.constraintPrimarys(missList);

        log.info("[SYNC] {} -> {} -> 元数据采集 -> Primary Constraint => 共计{} | 新增{} | 删除{}", database.getCatalogName(), database.getDatabaseName(), String.format("%5d", dealList.size()), String.format("%5d", extraList.size()), String.format("%5d", missList.size()) + (
                !missList.isEmpty() ? " => " + missList
                        .stream()
                        .map(constraintPrimary -> constraintPrimary.getTableName() + " - " + constraintPrimary.getConstraintName())
                        .collect(Collectors.joining(",")) : ""));
    }

}